home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / editors / stevie36.3 < prev    next >
Internet Message Format  |  1989-05-12  |  59KB

  1. Path: xanth!nic.MR.NET!umn-d-ub!rutgers!apple!oliveb!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i132:  stevie - vi editor clone v3.6, Part03/06
  5. Message-ID: <104419@sun.Eng.Sun.COM>
  6. Date: 12 May 89 03:06:43 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 2778
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: grwalter@watmath.waterloo.edu (Fred Walter)
  12. Posting-number: Volume 89, Issue 132
  13. Archive-name: editors/stevie36.3
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    makefile.amiga.lattice
  24. #    makefile.bsd
  25. #    makefile.dos
  26. #    makefile.mwc
  27. #    makefile.os2
  28. #    makefile.tos
  29. #    makefile.usg
  30. #    mark.c
  31. #    misccmds.c
  32. #    mk.c
  33. #    normal.c
  34. # This is archive 3 of a 6-part kit.
  35. # This archive created: Thu May 11 19:41:26 1989
  36. echo "extracting makefile.amiga.lattice"
  37. sed 's/^X//' << \SHAR_EOF > makefile.amiga.lattice
  38. X#
  39. X# Makefile for Lattice C 5.0 on Amiga
  40. X#
  41. X
  42. X.c.o:
  43. X    lc $(CFLAGS) $<
  44. X
  45. X#CFLAGS = -cu -ma -DAMIGA
  46. XCFLAGS = -cu -ma -O -DAMIGA
  47. XLINKFLAGS = NODEBUG
  48. XLIBS = lib:lc.lib
  49. X
  50. XMACH=    amiga.o
  51. X
  52. XOBJ1=    main.o edit.o linefunc.o normal.o cmdline.o charset.o
  53. XOBJ2=    format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o
  54. XOBJ3=    mk.o regexp.o regsub.o version.o
  55. XOBJ4=    s_io.o mark.o screen.o fileio.o param.o
  56. X
  57. XOBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH)
  58. X
  59. Xall: stevie
  60. X    say "done all"
  61. X
  62. Xstevie: $(OBJ) Makefile
  63. X    BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS)
  64. X
  65. Xclean:
  66. X    delete $(OBJ1)
  67. X    delete $(OBJ2)
  68. X    delete $(OBJ3)
  69. X    delete $(OBJ4)
  70. X    delete $(MACH)
  71. X    delete stevie
  72. SHAR_EOF
  73. echo "extracting makefile.bsd"
  74. sed 's/^X//' << \SHAR_EOF > makefile.bsd
  75. X#
  76. X# Makefile for BSD 4.3 UNIX
  77. X#
  78. X
  79. XCFLAGS = -O -DBSD
  80. X#CFLAGS = -pg -g -DBSD
  81. XLINTFLAGS = -DBSD
  82. X
  83. XMACHOBJ=    bsd.o
  84. XMACHSRC=    bsd.c
  85. X
  86. XSRC=    main.c edit.c linefunc.c normal.c cmdline.c charset.c \
  87. X    misccmds.c help.c dec.c inc.c search.c alloc.c \
  88. X    format_l.c mk.c regexp.c regsub.c version.c \
  89. X    s_io.c mark.c screen.c fileio.c param.c $(MACHSRC)
  90. X
  91. XOBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  92. X    misccmds.o help.o dec.o inc.o search.o alloc.o \
  93. X    format_l.o mk.o regexp.o regsub.o version.o \
  94. X    s_io.o mark.o screen.o fileio.o param.o $(MACHOBJ)
  95. X
  96. Xall : stevie
  97. X
  98. Xstevie : $(OBJ)
  99. X    $(CC) $(OBJ) $(CFLAGS) -o stevie
  100. X
  101. Xlint:
  102. X    lint $(LINTFLAGS) $(SRC)
  103. X
  104. Xclean :
  105. X    rm -f *.out *.o core stevie *.BAK
  106. SHAR_EOF
  107. echo "extracting makefile.dos"
  108. sed 's/^X//' << \SHAR_EOF > makefile.dos
  109. X#
  110. X# Makefile for DOS
  111. X#
  112. X# This makefile is set up for Microsoft C 5.1
  113. X#
  114. X
  115. X#
  116. X# Compact model lets us edit large files, but keep small model code
  117. X#
  118. XMODEL= /AC
  119. XCFLAGS = $(MODEL)
  120. X
  121. XMACH=    dos.obj
  122. X
  123. XOBJ=    main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
  124. X    mk.obj format_l.obj regexp.obj regsub.obj version.obj \
  125. X    misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
  126. X    s_io.obj mark.obj screen.obj fileio.obj param.obj $(MACH)
  127. X
  128. Xall:    stevie.exe
  129. X
  130. Xmain.obj:    main.c
  131. X    cl -c $(CFLAGS) main.c
  132. X
  133. Xformat_l.obj:    format_l.c
  134. X    cl -c $(CFLAGS) format_l.c
  135. X
  136. Xmk.obj:    mk.c
  137. X    cl -c $(CFLAGS) mk.c
  138. X
  139. Xregexp.obj:    regexp.c
  140. X    cl -c $(CFLAGS) regexp.c
  141. X
  142. Xregsub.obj:    regsub.c
  143. X    cl -c $(CFLAGS) regsub.c
  144. X
  145. Xversion.obj:    version.c
  146. X    cl -c $(CFLAGS) version.c
  147. X
  148. Xalloc.obj : alloc.c
  149. X    cl -c $(CFLAGS) alloc.c
  150. X
  151. Xedit.obj : edit.c
  152. X    cl -c $(CFLAGS) edit.c
  153. X
  154. Xs_io.obj : s_io.c
  155. X    cl -c $(CFLAGS) s_io.c
  156. X
  157. Xlinefunc.obj : linefunc.c
  158. X    cl -c $(CFLAGS) linefunc.c
  159. X
  160. Xnormal.obj : normal.c
  161. X    cl -c $(CFLAGS) normal.c
  162. X
  163. Xcmdline.obj : cmdline.c
  164. X    cl -c $(CFLAGS) cmdline.c
  165. X
  166. Xcharset.obj : charset.c
  167. X    cl -c $(CFLAGS) charset.c
  168. X
  169. Xmisccmds.obj : misccmds.c
  170. X    cl -c $(CFLAGS) misccmds.c
  171. X
  172. Xhelp.obj : help.c
  173. X    cl -c $(CFLAGS) help.c
  174. X
  175. Xdec.obj : dec.c
  176. X    cl -c $(CFLAGS) dec.c
  177. X
  178. Xinc.obj : inc.c
  179. X    cl -c $(CFLAGS) inc.c
  180. X
  181. Xsearch.obj : search.c
  182. X    cl -c $(CFLAGS) search.c
  183. X
  184. Xmark.obj : mark.c
  185. X    cl -c $(CFLAGS) mark.c
  186. X
  187. Xscreen.obj : screen.c
  188. X    cl -c $(CFLAGS) screen.c
  189. X
  190. Xfileio.obj : fileio.c
  191. X    cl -c $(CFLAGS) fileio.c
  192. X
  193. Xparam.obj : param.c
  194. X    cl -c $(CFLAGS) param.c
  195. X
  196. Xdos.obj : dos.c
  197. X    cl -c $(CFLAGS) dos.c
  198. X
  199. Xstevie.exe : $(OBJ)
  200. X    cl $(MODEL) *.obj c:\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE
  201. SHAR_EOF
  202. echo "extracting makefile.mwc"
  203. sed 's/^X//' << \SHAR_EOF > makefile.mwc
  204. X#
  205. X#
  206. X#
  207. X# Makefile for Mark Williams C
  208. X#
  209. XCFLAGS = -O -VPEEP 
  210. XLDFLAGS = -s -x -v
  211. XLINKER=ld
  212. X
  213. XOBJ1=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  214. X    format_l.o misccmds.o help.o dec.o inc.o 
  215. XOBJ2=    alloc.o search.o mk.o regexp.o regsub.o version.o s_io.o \
  216. X    mark.o screen.o fileio.o param.o tos.o
  217. X
  218. XSRC=    main.c edit.c linefunc.c normal.c cmdline.c charset.c \
  219. X    format_l.c misccmds.c help.c dec.c inc.c search.c alloc.c \
  220. X    mk.c regexp.c regsub.c version.c \
  221. X    s_io.c mark.c screen.c fileio.c param.c \
  222. X    tos.c
  223. X
  224. X
  225. Xall : stevie.ttp
  226. X
  227. Xstevie.a: $(OBJ1) $(OBJ2)
  228. X    ar rv stevie.a $(OBJ1)
  229. X    ar rv stevie.a $(OBJ2)
  230. X
  231. Xstevie.ttp:    stevie.a
  232. X    cc stevie.a $(LIBS) -o stevie.ttp
  233. SHAR_EOF
  234. echo "extracting makefile.os2"
  235. sed 's/^X//' << \SHAR_EOF > makefile.os2
  236. X#
  237. X# Makefile for OS/2
  238. X#
  239. X# The make command with OS/2 is really stupid.
  240. X#
  241. X
  242. X#
  243. X# Compact model lets us edit large files, but keep small model code
  244. X#
  245. XMODEL= -AC
  246. XCFLAGS = $(MODEL) -I..\regexp -J
  247. X
  248. XMACH=    os2.obj
  249. X
  250. XOBJ=    main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
  251. X    mk.obj format_l.obj regexp.obj regsub.obj version.obj \
  252. X    misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
  253. X    s_io.obj mark.obj screen.obj fileio.obj param.obj $(MACH)
  254. X
  255. Xall:    stevie.exe
  256. X
  257. Xmain.obj:    main.c
  258. X    cl -c $(CFLAGS) main.c
  259. X
  260. Xformat_l.obj:    format_l.c
  261. X    cl -c $(CFLAGS) format_l.c
  262. X
  263. Xmk.obj:    mk.c
  264. X    cl -c $(CFLAGS) mk.c
  265. X
  266. Xregexp.obj:    regexp.c
  267. X    cl -c $(CFLAGS) regexp.c
  268. X
  269. Xregsub.obj:    regsub.c
  270. X    cl -c $(CFLAGS) regsub.c
  271. X
  272. Xversion.obj:    version.c
  273. X    cl -c $(CFLAGS) version.c
  274. X
  275. Xalloc.obj : alloc.c
  276. X    cl -c $(CFLAGS) alloc.c
  277. X
  278. Xedit.obj : edit.c
  279. X    cl -c $(CFLAGS) edit.c
  280. X
  281. Xs_io.obj : s_io.c
  282. X    cl -c $(CFLAGS) s_io.c
  283. X
  284. Xlinefunc.obj : linefunc.c
  285. X    cl -c $(CFLAGS) linefunc.c
  286. X
  287. Xnormal.obj : normal.c
  288. X    cl -c $(CFLAGS) normal.c
  289. X
  290. Xcmdline.obj : cmdline.c
  291. X    cl -c $(CFLAGS) cmdline.c
  292. X
  293. Xcharset.obj : charset.c
  294. X    cl -c $(CFLAGS) charset.c
  295. X
  296. Xmisccmds.obj : misccmds.c
  297. X    cl -c $(CFLAGS) misccmds.c
  298. X
  299. Xhelp.obj : help.c
  300. X    cl -c $(CFLAGS) help.c
  301. X
  302. Xdec.obj : dec.c
  303. X    cl -c $(CFLAGS) dec.c
  304. X
  305. Xinc.obj : inc.c
  306. X    cl -c $(CFLAGS) inc.c
  307. X
  308. Xsearch.obj : search.c
  309. X    cl -c $(CFLAGS) search.c
  310. X
  311. Xmark.obj : mark.c
  312. X    cl -c $(CFLAGS) mark.c
  313. X
  314. Xscreen.obj : screen.c
  315. X    cl -c $(CFLAGS) screen.c
  316. X
  317. Xfileio.obj : fileio.c
  318. X    cl -c $(CFLAGS) fileio.c
  319. X
  320. Xparam.obj : param.c
  321. X    cl -c $(CFLAGS) param.c
  322. X
  323. Xos2.obj : os2.c
  324. X    cl -c $(CFLAGS) os2.c
  325. X
  326. Xstevie.exe : $(OBJ)
  327. X    cl $(MODEL) *.obj $(LIBS) -o stevie.exe /Lo # use protected mode lib.
  328. X    copy stevie.exe rstevie.exe
  329. X    bind rstevie.exe \lib\api.lib \lib\doscalls.lib
  330. SHAR_EOF
  331. echo "extracting makefile.tos"
  332. sed 's/^X//' << \SHAR_EOF > makefile.tos
  333. X#
  334. X# Makefile for the Atari ST - Megamax C compiler
  335. X#
  336. X
  337. XCFLAGS = -DMEGAMAX
  338. X
  339. X#    Megamax rule
  340. X.c.o:
  341. X    mmcc $(CFLAGS) $<
  342. X    mmimp $*.o
  343. X    mmlib rv vi.lib $*.o
  344. X
  345. XMACH=    tos.o
  346. X
  347. XOBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  348. X    format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  349. X    mk.o regexp.o regsub.o version.o \
  350. X    s_io.o mark.o screen.o fileio.o param.o $(MACH)
  351. X
  352. Xall : stevie.ttp
  353. X
  354. Xstevie.ttp : $(OBJ)
  355. X    $(LINKER) vi.lib $(LIBS) -o stevie.ttp
  356. X
  357. Xclean :
  358. X    $(RM) $(OBJ) vi.lib
  359. SHAR_EOF
  360. echo "extracting makefile.usg"
  361. sed 's/^X//' << \SHAR_EOF > makefile.usg
  362. X#
  363. X# Makefile for UNIX (System V)
  364. X#
  365. X
  366. XCFLAGS = -O -DUNIX
  367. X
  368. XMACH=    unix.o
  369. X
  370. XOBJ=    main.o edit.o linefunc.o normal.o cmdline.o charset.o \
  371. X    format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o \
  372. X    mk.o regexp.o regsub.o version.o \
  373. X    s_io.o mark.o screen.o fileio.o param.o $(MACH)
  374. X
  375. Xall : stevie
  376. X
  377. Xstevie : $(OBJ)
  378. X    $(CC) $(OBJ) $(LIBS) -o stevie
  379. X
  380. Xclean :
  381. X    rm $(OBJ)
  382. SHAR_EOF
  383. echo "extracting mark.c"
  384. sed 's/^X//' << \SHAR_EOF > mark.c
  385. X/*
  386. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  387. X *
  388. X * Code Contributions By : Tim Thompson           twitch!tjt
  389. X *                         Tony Andrews           onecom!wldrdg!tony 
  390. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  391. X */
  392. X
  393. X#include "stevie.h"
  394. X
  395. X#ifdef  MEGAMAX
  396. Xoverlay "mark"
  397. X#endif
  398. X
  399. X/*
  400. X * This file contains routines to maintain and manipulate marks. 
  401. X */
  402. X
  403. X#define NMARKS  10        /* max. # of marks that can be saved */
  404. X
  405. Xstruct mark {
  406. X    char            name;
  407. X    LPtr            pos;
  408. X};
  409. X
  410. Xstatic struct mark mlist[NMARKS];
  411. Xstatic struct mark pcmark;    /* previous context mark */
  412. Xstatic bool_t   pcvalid = FALSE;/* true if pcmark is valid */
  413. X
  414. X/*
  415. X * setmark(c) - set mark 'c' at current cursor position 
  416. X *
  417. X * Returns TRUE on success, FALSE if no room for mark or bad name given. 
  418. X */
  419. Xbool_t
  420. Xsetmark(c)
  421. X    char            c;
  422. X{
  423. X    int             i;
  424. X
  425. X    if (!isalpha(c))
  426. X    return FALSE;
  427. X
  428. X    /*
  429. X     * If there is already a mark of this name, then just use the existing
  430. X     * mark entry. 
  431. X     */
  432. X    for (i = 0; i < NMARKS; i++) {
  433. X    if (mlist[i].name == c) {
  434. X        mlist[i].pos = *Curschar;
  435. X        return TRUE;
  436. X    }
  437. X    }
  438. X
  439. X    /*
  440. X     * There wasn't a mark of the given name, so find a free slot 
  441. X     */
  442. X    for (i = 0; i < NMARKS; i++) {
  443. X    if (mlist[i].name == NUL) {    /* got a free one */
  444. X        mlist[i].name = c;
  445. X        mlist[i].pos = *Curschar;
  446. X        return TRUE;
  447. X    }
  448. X    }
  449. X    return FALSE;
  450. X}
  451. X
  452. X/*
  453. X * setpcmark() - set the previous context mark to the current position 
  454. X */
  455. Xvoid
  456. Xsetpcmark()
  457. X{
  458. X    pcmark.pos = *Curschar;
  459. X    pcvalid = TRUE;
  460. X}
  461. X
  462. X/*
  463. X * getmark(c) - find mark for char 'c' 
  464. X *
  465. X * Return pointer to LPtr or NULL if no such mark. 
  466. X */
  467. XLPtr           *
  468. Xgetmark(c)
  469. X    char            c;
  470. X{
  471. X    int             i;
  472. X
  473. X    if (c == '\'' || c == '`')    /* previous context mark */
  474. X    return pcvalid ? &(pcmark.pos) : (LPtr *) NULL;
  475. X
  476. X    for (i = 0; i < NMARKS; i++) {
  477. X    if (mlist[i].name == c)
  478. X        return &(mlist[i].pos);
  479. X    }
  480. X    return (LPtr *) NULL;
  481. X}
  482. X
  483. X/*
  484. X * clrall() - clear all marks 
  485. X *
  486. X * Used mainly when trashing the entire buffer during ":e" type commands 
  487. X */
  488. Xvoid
  489. Xclrall()
  490. X{
  491. X    int             i;
  492. X
  493. X    for (i = 0; i < NMARKS; i++)
  494. X    mlist[i].name = NUL;
  495. X    pcvalid = FALSE;
  496. X}
  497. X
  498. X/*
  499. X * clrmark(line) - clear any marks for 'line' 
  500. X *
  501. X * Used any time a line is deleted so we don't have marks pointing to
  502. X * non-existent lines. 
  503. X */
  504. Xvoid
  505. Xclrmark(line)
  506. X    LINE           *line;
  507. X{
  508. X    int             i;
  509. X
  510. X    for (i = 0; i < NMARKS; i++) {
  511. X    if (mlist[i].pos.linep == line)
  512. X        mlist[i].name = NUL;
  513. X    }
  514. X    if (pcvalid && (pcmark.pos.linep == line))
  515. X    pcvalid = FALSE;
  516. X}
  517. SHAR_EOF
  518. echo "extracting misccmds.c"
  519. sed 's/^X//' << \SHAR_EOF > misccmds.c
  520. X/*
  521. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  522. X *
  523. X * Code Contributions By : Tim Thompson           twitch!tjt
  524. X *                         Tony Andrews           onecom!wldrdg!tony 
  525. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  526. X */
  527. X
  528. X#include "stevie.h"
  529. X
  530. Xextern int      did_ai;
  531. X
  532. X/*
  533. X * OpenForward 
  534. X *
  535. X * Add a blank line below the current line. 
  536. X */
  537. X
  538. Xbool_t
  539. XOpenForward(can_ai)
  540. X    int             can_ai;
  541. X{
  542. X    LINE           *l;
  543. X    LPtr           *next;
  544. X    char           *s;        /* string to be moved to new line, if any */
  545. X    int             newindex = 0;    /* index of the cursor on the new
  546. X                     * line */
  547. X
  548. X    /*
  549. X     * If we're in insert mode, we need to move the remainder of the current
  550. X     * line onto the new line. Otherwise the new line is left blank. 
  551. X     */
  552. X    if (State == INSERT)
  553. X    s = &Curschar->linep->s[Curschar->index];
  554. X    else
  555. X    s = "";
  556. X
  557. X    if ((next = nextline(Curschar)) == NULL)    /* open on last line */
  558. X    next = Fileend;
  559. X
  560. X    /*
  561. X     * By asking for as much space as the prior line had we make sure that
  562. X     * we'll have enough space for any auto-indenting. 
  563. X     */
  564. X    l = newline(strlen(Curschar->linep->s) + SLOP);
  565. X    if (l == NULL) {
  566. X    emsg("out of memory");
  567. X    beep();
  568. X    sleep(2);
  569. X    return (FALSE);
  570. X    }
  571. X    if (can_ai && P(P_AI)) {
  572. X    char           *p;
  573. X
  574. X    /*
  575. X     * Copy prior line, and truncate after white space 
  576. X     */
  577. X    strcpy(l->s, Curschar->linep->s);
  578. X
  579. X    for (p = l->s; *p == ' ' || *p == TAB; p++);
  580. X    *p = NUL;
  581. X    newindex = p - l->s;
  582. X    AppendToInsbuff(l->s);
  583. X    if (*s != NUL)
  584. X        strcat(l->s, s);
  585. X
  586. X    /*
  587. X     * If we just did an auto-indent, then we didn't type anything on the
  588. X     * prior line, and it should be truncated. 
  589. X     */
  590. X    if (did_ai)
  591. X        Curschar->linep->s[0] = NUL;
  592. X
  593. X    did_ai = TRUE;
  594. X    } else if (*s != NUL) {
  595. X    strcpy(l->s, s);    /* copy string to new line */
  596. X    }
  597. X    if (State == INSERT)    /* truncate current line at cursor */
  598. X    *s = NUL;
  599. X
  600. X    Curschar->linep->next = l;    /* link neighbors to new line */
  601. X    next->linep->prev = l;
  602. X
  603. X    l->prev = Curschar->linep;    /* link new line to neighbors */
  604. X    l->next = next->linep;
  605. X
  606. X    if (next == Fileend) {    /* new line at end */
  607. X    l->num = Curschar->linep->num + LINEINC;
  608. X    } else if ((l->prev->num) + 1 == l->next->num) {    /* no gap, renumber */
  609. X    renum();
  610. X    } else {            /* stick it in the middle */
  611. X    long            lnum;
  612. X
  613. X    lnum = (l->prev->num + l->next->num) / 2;
  614. X    l->num = lnum;
  615. X    }
  616. X
  617. X    *Curschar = *nextline(Curschar);    /* cursor moves down */
  618. X    Curschar->index = newindex;
  619. X
  620. X    S_NOT_VALID;
  621. X    CHANGED;
  622. X
  623. X    return (TRUE);
  624. X}
  625. X
  626. X/*
  627. X * OpenBackward 
  628. X *
  629. X * Add a blank line above the current line. 
  630. X */
  631. X
  632. Xbool_t
  633. XOpenBackward(can_ai)
  634. X    int             can_ai;
  635. X{
  636. X    LINE           *l;
  637. X    LINE           *prev;
  638. X    int             newindex = 0;    /* index of the cursor on the new
  639. X                     * line */
  640. X
  641. X    prev = Curschar->linep->prev;
  642. X
  643. X    l = newline(strlen(Curschar->linep->s) + SLOP);
  644. X    if (l == NULL) {
  645. X    emsg("out of memory");
  646. X    beep();
  647. X    sleep(2);
  648. X    return (FALSE);
  649. X    }
  650. X    Curschar->linep->prev = l;    /* link neighbors to new line */
  651. X    prev->next = l;
  652. X
  653. X    l->next = Curschar->linep;    /* link new line to neighbors */
  654. X    l->prev = prev;
  655. X
  656. X    if (can_ai && P(P_AI)) {
  657. X    char           *p;
  658. X
  659. X    /*
  660. X     * Copy current line, and truncate after white space 
  661. X     */
  662. X    strcpy(l->s, Curschar->linep->s);
  663. X
  664. X    for (p = l->s; *p == ' ' || *p == TAB; p++);
  665. X    *p = NUL;
  666. X    newindex = p - l->s;
  667. X    AppendToInsbuff(l->s);
  668. X
  669. X    did_ai = TRUE;
  670. X    }
  671. X    Curschar->linep = Curschar->linep->prev;
  672. X    Curschar->index = newindex;
  673. X
  674. X    if (prev == Filetop->linep) {    /* new start of file */
  675. X    Filemem->linep = l;
  676. X    renum();
  677. X    } else if ((l->prev->num) + 1 == l->next->num) {    /* no gap, renumber */
  678. X    renum();
  679. X    } else {            /* stick it in the middle */
  680. X    long            lnum;
  681. X
  682. X    lnum = (l->prev->num + l->next->num) / 2;
  683. X    l->num = lnum;
  684. X    }
  685. X
  686. X    S_NOT_VALID;
  687. X    CHANGED;
  688. X
  689. X    return (TRUE);
  690. X}
  691. X
  692. Xint
  693. Xcntllines(pbegin, pend)
  694. X    LPtr           *pbegin, *pend;
  695. X{
  696. X    register LINE  *lp;
  697. X    register int    lnum = 1;
  698. X
  699. X    for (lp = pbegin->linep; lp != pend->linep; lp = lp->next)
  700. X    lnum++;
  701. X
  702. X    return (lnum);
  703. X}
  704. X
  705. X/*
  706. X * plines(s) - return the number of physical screen lines taken by the
  707. X *             line pointed to by 's'
  708. X */
  709. X
  710. Xint
  711. Xplines(s)
  712. X    register char  *s;
  713. X{
  714. X    register int    col = 0;
  715. X
  716. X    if (*s == NUL)        /* empty line */
  717. X    return 1;
  718. X
  719. X    for (; *s != NUL; s++) {
  720. X    if (*s == TAB && !P(P_LS))
  721. X        col += P(P_TS) - (col % P(P_TS));
  722. X    else
  723. X        col += chars[*s].ch_size;
  724. X    }
  725. X
  726. X    /*
  727. X     * If list mode is on, then the '$' at the end of the line takes up one
  728. X     * extra column. 
  729. X     */
  730. X    if (P(P_LS))
  731. X    col += 1;
  732. X
  733. X    /*
  734. X     * If 'number' mode is on, add another 8. 
  735. X     */
  736. X    if (P(P_NU))
  737. X    col += 8;
  738. X
  739. X    return ((col + (Columns - 1)) / Columns);
  740. X}
  741. X
  742. Xvoid
  743. Xfileinfo()
  744. X{
  745. X    long            l1, l2;
  746. X    char            buf[MAX_COLUMNS + 1];
  747. X
  748. X    if (bufempty()) {
  749. X    msg("Buffer Empty");
  750. X    return;
  751. X    }
  752. X    l1 = cntllines(Filemem, Curschar);
  753. X    l2 = cntllines(Filemem, Fileend) - 1;
  754. X    sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --",
  755. X        (Filename != NULL) ? Filename : "No File",
  756. X        Changed ? " [Modified]" : "",
  757. X        l1, l2, (l1 * 100) / l2);
  758. X    msg(buf);
  759. X}
  760. X
  761. X/*
  762. X * gotoline(n) - return a pointer to line 'n' 
  763. X *
  764. X * Returns a pointer to the last line of the file if n is zero, or beyond the
  765. X * end of the file. 
  766. X */
  767. XLPtr           *
  768. Xgotoline(n)
  769. X    int             n;
  770. X{
  771. X    static LPtr     l;
  772. X
  773. X    l.index = 0;
  774. X
  775. X    if (n == 0)
  776. X    l = *prevline(Fileend);
  777. X    else {
  778. X    LPtr           *p;
  779. X
  780. X    for (l = *Filemem; --n > 0; l = *p)
  781. X        if ((p = nextline(&l)) == NULL)
  782. X        break;
  783. X    }
  784. X    return &l;
  785. X}
  786. X
  787. Xvoid
  788. Xinschar(c)
  789. X    char            c;
  790. X{
  791. X    register char  *p;
  792. X    register char  *pend;
  793. X
  794. X    /* make room for the new char. */
  795. X    if (!canincrease(1))
  796. X    return;
  797. X
  798. X    p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
  799. X    pend = &Curschar->linep->s[Curschar->index];
  800. X
  801. X    for (; p > pend; p--)
  802. X    *p = *(p - 1);
  803. X
  804. X    *p = c;
  805. X
  806. X    if (RedrawingDisabled) {
  807. X    Curschar->index++;
  808. X    return;
  809. X    }
  810. X    /*
  811. X     * If we're in insert mode and showmatch mode is set, then check for
  812. X     * right parens and braces. If there isn't a match, then beep. If there
  813. X     * is a match AND it's on the screen, then flash to it briefly. If it
  814. X     * isn't on the screen, don't do anything. 
  815. X     */
  816. X    if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
  817. X    LPtr           *lpos, csave;
  818. X
  819. X    if ((lpos = showmatch()) == NULL)    /* no match, so beep */
  820. X        beep();
  821. X    else if (LINEOF(lpos) >= LINEOF(Topchar)) {
  822. X        /* show the new char first */
  823. X        s_refresh(VALID_TO_CURSCHAR);
  824. X        csave = *Curschar;
  825. X        *Curschar = *lpos;    /* move to matching char */
  826. X        cursupdate(UPDATE_CURSOR);
  827. X        windgoto(Cursrow, Curscol);
  828. X        delay();        /* brief pause */
  829. X        *Curschar = csave;    /* restore cursor position */
  830. X        cursupdate(UPDATE_ALL);
  831. X    }
  832. X    }
  833. X    inc(Curschar);
  834. X
  835. X    CHANGED;
  836. X}
  837. X
  838. Xvoid
  839. Xinsstr(s)
  840. X    register char  *s;
  841. X{
  842. X    register char  *p;
  843. X    register char  *pend;
  844. X    register int    n = strlen(s);
  845. X
  846. X    /* Move everything in the file over to make */
  847. X    /* room for the new string. */
  848. X    if (!canincrease(n))
  849. X    return;
  850. X
  851. X    p = &Curschar->linep->s[strlen(Curschar->linep->s) + n];
  852. X    pend = &Curschar->linep->s[Curschar->index];
  853. X
  854. X    for (; p > pend; p--)
  855. X    *p = *(p - n);
  856. X
  857. X    for (; n > 0; n--) {
  858. X    *p++ = *s++;
  859. X    Curschar->index++;
  860. X    }
  861. X    CHANGED;
  862. X}
  863. X
  864. Xbool_t
  865. Xdelchar(fixpos, undo)
  866. X    bool_t          fixpos;    /* if TRUE fix the cursor position when done */
  867. X    bool_t          undo;    /* if TRUE put char deleted into Undo buffer */
  868. X{
  869. X    int             i;
  870. X
  871. X    /* Check for degenerate case; there's nothing in the file. */
  872. X    if (bufempty())
  873. X    return FALSE;
  874. X
  875. X    if (lineempty(Curschar))    /* can't do anything */
  876. X    return FALSE;
  877. X
  878. X    if (undo)
  879. X    AppendToUndobuff(mkstr(gchar(Curschar)));
  880. X
  881. X    /* Delete the char. at Curschar by shifting everything in the line down. */
  882. X    for (i = Curschar->index + 1; i < Curschar->linep->size; i++)
  883. X    Curschar->linep->s[i - 1] = Curschar->linep->s[i];
  884. X
  885. X    /*
  886. X     * If we just took off the last character of a non-blank line, we don't
  887. X     * want to end up positioned at the newline. 
  888. X     */
  889. X    if (fixpos) {
  890. X    if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT)
  891. X        Curschar->index--;
  892. X    }
  893. X    CHANGED;
  894. X    return TRUE;
  895. X}
  896. X
  897. Xvoid
  898. Xdelline(nlines)
  899. X    int             nlines;
  900. X{
  901. X    register LINE  *p;
  902. X    register LINE  *q;
  903. X
  904. X    while (nlines-- > 0) {
  905. X
  906. X    if (bufempty())        /* nothing to delete */
  907. X        break;
  908. X
  909. X    if (buf1line()) {    /* just clear the line */
  910. X        Curschar->linep->s[0] = NUL;
  911. X        Curschar->index = 0;
  912. X        break;
  913. X    }
  914. X    p = Curschar->linep->prev;
  915. X    q = Curschar->linep->next;
  916. X
  917. X    if (p == Filetop->linep) {    /* first line of file so... */
  918. X        Filemem->linep = q;    /* adjust start of file */
  919. X        Topchar->linep = q;    /* and screen */
  920. X    }
  921. X    p->next = q;
  922. X    q->prev = p;
  923. X
  924. X    clrmark(Curschar->linep);    /* clear marks for the line */
  925. X
  926. X    /*
  927. X     * If deleting the top line on the screen, adjust Topchar 
  928. X     */
  929. X    if (Topchar->linep == Curschar->linep)
  930. X        Topchar->linep = q;
  931. X
  932. X    free(Curschar->linep->s);
  933. X    free((char *) (Curschar->linep));
  934. X
  935. X    Curschar->linep = q;
  936. X    Curschar->index = 0;    /* is this right? */
  937. X
  938. X    S_NOT_VALID;
  939. X    CHANGED;
  940. X
  941. X    /* If we delete the last line in the file, back up */
  942. X    if (Curschar->linep == Fileend->linep) {
  943. X        Curschar->linep = Curschar->linep->prev;
  944. X        /* and don't try to delete any more lines */
  945. X        break;
  946. X    }
  947. X    }
  948. X}
  949. SHAR_EOF
  950. echo "extracting mk.c"
  951. sed 's/^X//' << \SHAR_EOF > mk.c
  952. X/*
  953. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  954. X *
  955. X * Code Contributions By : Tim Thompson           twitch!tjt
  956. X *                         Tony Andrews           onecom!wldrdg!tony 
  957. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  958. X */
  959. X
  960. X#include "stevie.h"
  961. X
  962. Xchar           *
  963. Xmkline(n)
  964. X    int             n;
  965. X{
  966. X    static char     lbuf[9];
  967. X    int             i = 6;
  968. X
  969. X    strcpy(lbuf, "        ");
  970. X
  971. X    lbuf[i--] = (char) ((n % 10) + '0');
  972. X    n /= 10;
  973. X    if (n != 0) {
  974. X    lbuf[i--] = (char) ((n % 10) + '0');
  975. X    n /= 10;
  976. X    }
  977. X    if (n != 0) {
  978. X    lbuf[i--] = (char) ((n % 10) + '0');
  979. X    n /= 10;
  980. X    }
  981. X    if (n != 0) {
  982. X    lbuf[i--] = (char) ((n % 10) + '0');
  983. X    n /= 10;
  984. X    }
  985. X    if (n != 0)
  986. X    lbuf[i] = (char) ((n % 10) + '0');
  987. X
  988. X    return lbuf;
  989. X}
  990. X
  991. Xchar           *
  992. Xmkstr(c)
  993. X    char            c;
  994. X{
  995. X    static char     s[2];
  996. X
  997. X    s[0] = c;
  998. X    s[1] = NUL;
  999. X
  1000. X    return s;
  1001. X}
  1002. SHAR_EOF
  1003. echo "extracting normal.c"
  1004. sed 's/^X//' << \SHAR_EOF > normal.c
  1005. X/*
  1006. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  1007. X *
  1008. X * Code Contributions By : Tim Thompson           twitch!tjt
  1009. X *                         Tony Andrews           onecom!wldrdg!tony 
  1010. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  1011. X */
  1012. X
  1013. X/*
  1014. X * This file contains the main routine for processing characters in command
  1015. X * mode as well as routines for handling the operators. 
  1016. X */
  1017. X
  1018. X#include "stevie.h"
  1019. X
  1020. Xstatic void
  1021. Xdoshift(), dodelete(), doput(), dochange();
  1022. Xstatic void
  1023. X                startinsert();
  1024. Xstatic          bool_t
  1025. X                dojoin();
  1026. Xstatic          bool_t
  1027. X                doyank();
  1028. X
  1029. X/*
  1030. X * Macro evaluates true if char 'c' is a valid identifier character 
  1031. X */
  1032. X#define IDCHAR(c)       (isalpha(c) || isdigit(c) || (c) == '_')
  1033. X
  1034. X/*
  1035. X * Operators 
  1036. X */
  1037. X#define NOP     0        /* no pending operation */
  1038. X#define DELETE  1
  1039. X#define YANK    2
  1040. X#define CHANGE  3
  1041. X#define LSHIFT  4
  1042. X#define RSHIFT  5
  1043. X
  1044. X#define CLEAROP (operator = NOP)/* clear any pending operator */
  1045. X
  1046. Xstatic int      operator = NOP;    /* current pending operator */
  1047. X
  1048. X/*
  1049. X * When a cursor motion command is made, it is marked as being a character or
  1050. X * line oriented motion. Then, if an operator is in effect, the operation
  1051. X * becomes character or line oriented accordingly. 
  1052. X *
  1053. X * Character motions are marked as being inclusive or not. Most char. motions
  1054. X * are inclusive, but some (e.g. 'w') are not. 
  1055. X *
  1056. X * Generally speaking, every command in normal() should either clear any pending
  1057. X * operator (with CLEAROP), or set the motion type variable. 
  1058. X */
  1059. X
  1060. X/*
  1061. X * Motion types 
  1062. X */
  1063. X#define MBAD    (-1)        /* 'bad' motion type marks unusable yank buf */
  1064. X#define MCHAR   0
  1065. X#define MLINE   1
  1066. X
  1067. Xstatic int      mtype;        /* type of the current cursor motion */
  1068. Xstatic bool_t   mincl;        /* true if char motion is inclusive */
  1069. Xstatic int      ybtype = MBAD;
  1070. Xstatic int      ybcrossline = FALSE;
  1071. X
  1072. Xstatic LPtr     startop;    /* cursor pos. at start of operator */
  1073. X
  1074. X/*
  1075. X * Operators can have counts either before the operator, or between the
  1076. X * operator and the following cursor motion as in: 
  1077. X *
  1078. X * d3w or 3dw 
  1079. X *
  1080. X * If a count is given before the operator, it is saved in opnum. If normal() is
  1081. X * called with a pending operator, the count in opnum (if present) overrides
  1082. X * any count that came later. 
  1083. X */
  1084. Xstatic int      opnum = 0;
  1085. X
  1086. X#define DEFAULT1(x)     (((x) == 0) ? 1 : (x))
  1087. X
  1088. X/*
  1089. X * normal 
  1090. X *
  1091. X * Execute a command in normal mode. 
  1092. X */
  1093. X
  1094. Xvoid
  1095. Xnormal(c)
  1096. X    char            c;
  1097. X{
  1098. X    char           *p;
  1099. X    int             n;
  1100. X    int             nn;
  1101. X    bool_t          flag = FALSE;
  1102. X    int             type = 0;    /* used in some operations to modify type */
  1103. X    int             dir = FORWARD;    /* search direction */
  1104. X    char            nchar = NUL;
  1105. X    bool_t          finish_op;
  1106. X    LPtr            temp_Curschar;
  1107. X
  1108. X    last_command = NUL;
  1109. X    /*
  1110. X     * If there is an operator pending, then the command we take this time
  1111. X     * will terminate it. Finish_op tells us to finish the operation before
  1112. X     * returning this time (unless the operation was cancelled). 
  1113. X     */
  1114. X    finish_op = (operator != NOP);
  1115. X
  1116. X    /*
  1117. X     * If we're in the middle of an operator AND we had a count before the
  1118. X     * operator, then that count overrides the current value of Prenum. What
  1119. X     * this means effectively, is that commands like "3dw" get turned into
  1120. X     * "d3w" which makes things fall into place pretty neatly. 
  1121. X     */
  1122. X    if (finish_op) {
  1123. X    if (opnum != 0)
  1124. X        Prenum = opnum;
  1125. X    } else
  1126. X    opnum = 0;
  1127. X
  1128. X    switch (c) {
  1129. X
  1130. X      case K_HELP:
  1131. X    CLEAROP;
  1132. X    if (help())
  1133. X        s_clear();
  1134. X    break;
  1135. X
  1136. X      case CTRL('L'):
  1137. X    CLEAROP;
  1138. X    s_clear();
  1139. X    break;
  1140. X
  1141. X      case CTRL('D'):
  1142. X    CLEAROP;
  1143. X    if (Prenum)
  1144. X        P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  1145. X    scrollup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1146. X    onedown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1147. X    break;
  1148. X
  1149. X      case CTRL('U'):
  1150. X    CLEAROP;
  1151. X    if (Prenum)
  1152. X        P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
  1153. X    scrolldown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1154. X    oneup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
  1155. X    break;
  1156. X
  1157. X      case CTRL('F'):
  1158. X    CLEAROP;
  1159. X    if (nextline(Topchar) == NULL) {
  1160. X        beep();
  1161. X        break;
  1162. X    }
  1163. X    Prenum = DEFAULT1(Prenum);
  1164. X    while (Prenum > 0) {
  1165. X        *Curschar = *prevline(Botchar);
  1166. X        *Topchar = *Curschar;
  1167. X        Topchar->index = 0;
  1168. X        Update_Botchar();
  1169. X        Prenum--;
  1170. X    }
  1171. X    beginline(TRUE);
  1172. X    s_clear();
  1173. X    break;
  1174. X
  1175. X      case CTRL('B'):
  1176. X    CLEAROP;
  1177. X    if (prevline(Topchar) == NULL) {
  1178. X        beep();
  1179. X        break;
  1180. X    }
  1181. X    Prenum = DEFAULT1(Prenum);
  1182. X    while (Prenum > 0) {
  1183. X        *Curschar = *Topchar;
  1184. X        n = Rows - 1;
  1185. X        {
  1186. X        LPtr           *lp = Curschar;
  1187. X        int             l = 0;
  1188. X
  1189. X        while ((l < n) && (lp != NULL)) {
  1190. X            l += plines(lp->linep->s);
  1191. X            *Topchar = *lp;
  1192. X            lp = prevline(lp);
  1193. X        }
  1194. X        }
  1195. X        Topchar->index = 0;
  1196. X        Prenum--;
  1197. X    }
  1198. X    beginline(TRUE);
  1199. X    s_clear();
  1200. X    break;
  1201. X
  1202. X      case CTRL('E'):
  1203. X    CLEAROP;
  1204. X    scrollup(DEFAULT1(Prenum));
  1205. X        if (LINEOF(Curschar) < LINEOF(Topchar))
  1206. X        Curschar->linep = Topchar->linep;
  1207. X    break;
  1208. X
  1209. X      case CTRL('Y'):
  1210. X    CLEAROP;
  1211. X    scrolldown(DEFAULT1(Prenum));
  1212. X    Update_Botchar();
  1213. X    if (LINEOF(Curschar) >= LINEOF(Botchar)) {
  1214. X        LPtr           *lp;
  1215. X
  1216. X        lp = prevline(Botchar);
  1217. X        if (lp == NULL)
  1218. X        lp = Topchar;
  1219. X        Curschar->linep = lp->linep;
  1220. X    }
  1221. X    break;
  1222. X
  1223. X      case 'z':
  1224. X    CLEAROP;
  1225. X    S_CHECK_TOPCHAR_AND_BOTCHAR;
  1226. X    switch (vgetc()) {
  1227. X      case NL:        /* put Curschar at top of screen */
  1228. X      case CR:
  1229. X        *Topchar = *Curschar;
  1230. X        Topchar->index = 0;
  1231. X        break;
  1232. X
  1233. X      case '.':        /* put Curschar in middle of screen */
  1234. X        n = Rows / 2;
  1235. X        goto dozcmd;
  1236. X
  1237. X      case '-':        /* put Curschar at bottom of screen */
  1238. X        n = Rows - 1;
  1239. X        /* FALLTHROUGH */
  1240. X
  1241. X    dozcmd:
  1242. X        {
  1243. X        register LPtr  *lp = Curschar;
  1244. X        register int    l = 0;
  1245. X
  1246. X        while ((l < n) && (lp != NULL)) {
  1247. X            l += plines(lp->linep->s);
  1248. X            *Topchar = *lp;
  1249. X            lp = prevline(lp);
  1250. X        }
  1251. X        }
  1252. X        Topchar->index = 0;
  1253. X        break;
  1254. X
  1255. X      default:
  1256. X        beep();
  1257. X    }
  1258. X    break;
  1259. X
  1260. X      case CTRL('G'):
  1261. X    CLEAROP;
  1262. X    fileinfo();
  1263. X    break;
  1264. X
  1265. X      case 'G':
  1266. X    mtype = MLINE;
  1267. X    *Curschar = *gotoline(Prenum);
  1268. X    if (!UndoInProgress) {
  1269. X        beginline(TRUE);
  1270. X        S_CHECK_TOPCHAR_AND_BOTCHAR;
  1271. X    }
  1272. X    break;
  1273. X
  1274. X      case 'H':
  1275. X    mtype = MLINE;
  1276. X    *Curschar = *Topchar;
  1277. X    for (n = Prenum; n && onedown(1); n--);
  1278. X    beginline(TRUE);
  1279. X    break;
  1280. X
  1281. X      case 'M':
  1282. X    mtype = MLINE;
  1283. X    *Curschar = *Topchar;
  1284. X    for (n = 0; n < Rows / 2 && onedown(1); n++);
  1285. X    beginline(TRUE);
  1286. X    break;
  1287. X
  1288. X      case 'L':
  1289. X    mtype = MLINE;
  1290. X    *Curschar = *prevline(Botchar);
  1291. X    for (n = Prenum; n && oneup(1); n--);
  1292. X    beginline(TRUE);
  1293. X    break;
  1294. X
  1295. X      case 'l':
  1296. X      case K_RARROW:
  1297. X      case ' ':
  1298. X    mtype = MCHAR;
  1299. X    mincl = FALSE;
  1300. X    n = DEFAULT1(Prenum);
  1301. X    while (n--) {
  1302. X        if (!oneright()) {
  1303. X        if (operator != DELETE && operator != CHANGE) {
  1304. X            beep();
  1305. X        } else {
  1306. X            if (lineempty(Curschar)) {
  1307. X            CLEAROP;
  1308. X            beep();
  1309. X            } else {
  1310. X            mincl = TRUE;
  1311. X            }
  1312. X        }
  1313. X        break;
  1314. X        }
  1315. X    }
  1316. X    set_want_col = TRUE;
  1317. X    break;
  1318. X
  1319. X      case 'h':
  1320. X      case K_LARROW:
  1321. X      case CTRL('H'):
  1322. X    mtype = MCHAR;
  1323. X    mincl = FALSE;
  1324. X    Prenum = DEFAULT1(Prenum);
  1325. X    n = Prenum;
  1326. X    while (n--) {
  1327. X        if (!oneleft()) {
  1328. X        if (operator != DELETE && operator != CHANGE) {
  1329. X            beep();
  1330. X        } else if (Prenum == 1) {
  1331. X            CLEAROP;
  1332. X            beep();
  1333. X        }
  1334. X        break;
  1335. X        }
  1336. X    }
  1337. X    set_want_col = TRUE;
  1338. X    break;
  1339. X
  1340. X      case '-':
  1341. X    flag = TRUE;
  1342. X    /* FALLTHROUGH */
  1343. X
  1344. X      case 'k':
  1345. X      case K_UARROW:
  1346. X      case CTRL('P'):
  1347. X    mtype = MLINE;
  1348. X    if (!oneup(DEFAULT1(Prenum))) {
  1349. X        CLEAROP;
  1350. X        beep();
  1351. X    } else if (flag)
  1352. X        beginline(TRUE);
  1353. X    break;
  1354. X
  1355. X      case '+':
  1356. X      case CR:
  1357. X      case NL:
  1358. X    flag = TRUE;
  1359. X    /* FALLTHROUGH */
  1360. X
  1361. X      case 'j':
  1362. X      case K_DARROW:
  1363. X      case CTRL('N'):
  1364. X    mtype = MLINE;
  1365. X    if (!onedown(DEFAULT1(Prenum))) {
  1366. X        CLEAROP;
  1367. X        beep();
  1368. X    } else if (flag)
  1369. X        beginline(TRUE);
  1370. X    break;
  1371. X
  1372. X    /*
  1373. X     * This is a strange motion command that helps make operators more
  1374. X     * logical. It is actually implemented, but not documented in the
  1375. X     * real 'vi'. This motion command actually refers to "the current
  1376. X     * line". Commands like "dd" and "yy" are really an alternate form of
  1377. X     * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  1378. X     * lines. 
  1379. X     */
  1380. X      case '_':
  1381. Xlineop:
  1382. X    mtype = MLINE;
  1383. X    if (!onedown(DEFAULT1(Prenum) - 1)) {
  1384. X        CLEAROP;
  1385. X        beep();
  1386. X    } else
  1387. X        beginline(TRUE);
  1388. X    break;
  1389. X
  1390. X      case '|':
  1391. X    mtype = MCHAR;
  1392. X    mincl = TRUE;
  1393. X    beginline(FALSE);
  1394. X    if (Prenum > 0)
  1395. X        coladvance(Curschar, Prenum - 1);
  1396. X    Curswant = Prenum - 1;
  1397. X    break;
  1398. X
  1399. X      case CTRL(']'):        /* :ta to current identifier */
  1400. X    CLEAROP;
  1401. X    {
  1402. X        char            ch;
  1403. X        LPtr            save;
  1404. X
  1405. X        save = *Curschar;
  1406. X        /*
  1407. X         * First back up to start of identifier. This doesn't match the
  1408. X         * real vi but I like it a little better and it shouldn't bother
  1409. X         * anyone. 
  1410. X         */
  1411. X        ch = gchar(Curschar);
  1412. X        while (IDCHAR(ch)) {
  1413. X        if (!oneleft())
  1414. X            break;
  1415. X        ch = gchar(Curschar);
  1416. X        }
  1417. X        if (!IDCHAR(ch))
  1418. X        oneright();
  1419. X
  1420. X        stuffReadbuff(":ta ");
  1421. X        /*
  1422. X         * Now grab the chars in the identifier 
  1423. X         */
  1424. X        ch = gchar(Curschar);
  1425. X        while (IDCHAR(ch)) {
  1426. X        stuffReadbuff(mkstr(ch));
  1427. X        if (!oneright())
  1428. X            break;
  1429. X        ch = gchar(Curschar);
  1430. X        }
  1431. X        stuffReadbuff("\n");
  1432. X
  1433. X        *Curschar = save;    /* restore, in case of error */
  1434. X    }
  1435. X    break;
  1436. X
  1437. X      case '%':
  1438. X    S_CHECK_TOPCHAR_AND_BOTCHAR;
  1439. X    mtype = MCHAR;
  1440. X    mincl = TRUE;
  1441. X    {
  1442. X        LPtr           *pos;
  1443. X
  1444. X        if ((pos = showmatch()) == NULL) {
  1445. X        CLEAROP;
  1446. X        beep();
  1447. X        } else {
  1448. X        setpcmark();
  1449. X        *Curschar = *pos;
  1450. X        set_want_col = TRUE;
  1451. X        }
  1452. X    }
  1453. X    break;
  1454. X
  1455. X    /*
  1456. X     * Word Motions 
  1457. X     */
  1458. X
  1459. X      case 'B':
  1460. X    type = 1;
  1461. X    /* FALLTHROUGH */
  1462. X
  1463. X      case 'b':
  1464. X    mtype = MCHAR;
  1465. X    mincl = FALSE;
  1466. X    set_want_col = TRUE;
  1467. X    for (n = DEFAULT1(Prenum); n > 0; n--) {
  1468. X        LPtr           *pos;
  1469. X
  1470. X        if ((Curschar->linep->prev == Filetop->linep)
  1471. X        && (Curschar->index == 0)) {
  1472. X        CLEAROP;
  1473. X        beep();
  1474. X        break;
  1475. X        }
  1476. X        pos = bck_word(Curschar, type);
  1477. X        if (pos == NULL) {
  1478. X        CLEAROP;
  1479. X        beep();
  1480. X        *Curschar = *gotoline(1);    /* goto top of file */
  1481. X        } else
  1482. X        *Curschar = *pos;
  1483. X    }
  1484. X    break;
  1485. X
  1486. X      case 'W':
  1487. X    type = 1;
  1488. X    /* FALLTHROUGH */
  1489. X
  1490. X      case 'w':
  1491. X    /*
  1492. X     * This is a little strange. To match what the real vi does, we
  1493. X     * effectively map 'cw' to 'ce', and 'cW' to 'cE'. This seems
  1494. X     * impolite at first, but it's really more what we mean when we say
  1495. X     * 'cw'. 
  1496. X     */
  1497. X    if (operator == CHANGE)
  1498. X        goto do_e_cmd;
  1499. X
  1500. X    mtype = MCHAR;
  1501. X    mincl = FALSE;
  1502. X    set_want_col = TRUE;
  1503. X    for (n = DEFAULT1(Prenum); n > 0; n--) {
  1504. X        LPtr           *pos;
  1505. X
  1506. X        if ((pos = fwd_word(Curschar, type)) == NULL) {
  1507. X        CLEAROP;
  1508. X        beep();
  1509. X        break;
  1510. X        } else
  1511. X        *Curschar = *pos;
  1512. X    }
  1513. X    break;
  1514. X
  1515. X      case 'E':
  1516. X    type = 1;
  1517. X    /* FALLTHROUGH */
  1518. X
  1519. X      case 'e':
  1520. Xdo_e_cmd:
  1521. X    mtype = MCHAR;
  1522. X    mincl = TRUE;
  1523. X    set_want_col = TRUE;
  1524. X    for (n = DEFAULT1(Prenum); n > 0; n--) {
  1525. X        LPtr           *pos;
  1526. X
  1527. X        if ((pos = end_word(Curschar, type)) == NULL) {
  1528. X        CLEAROP;
  1529. X        beep();
  1530. X        break;
  1531. X        } else
  1532. X        *Curschar = *pos;
  1533. X    }
  1534. X    break;
  1535. X
  1536. X      case '$':
  1537. X    mtype = MCHAR;
  1538. X    mincl = TRUE;
  1539. X    while (oneright());
  1540. X    Curswant = 999;        /* so we stay at the end */
  1541. X    break;
  1542. X
  1543. X      case '^':
  1544. X    flag = TRUE;
  1545. X    /* FALLTHROUGH */
  1546. X
  1547. X      case '0':
  1548. X    mtype = MCHAR;
  1549. X    mincl = TRUE;
  1550. X    beginline(flag);
  1551. X    break;
  1552. X
  1553. X      case 'A':
  1554. X    set_want_col = TRUE;
  1555. X    while (oneright());
  1556. X    ResetBuffers();
  1557. X    AppendToRedobuff("A");
  1558. X    goto doAPPENDcmd;
  1559. X
  1560. X      case 'a':
  1561. X    ResetBuffers();
  1562. X    AppendToRedobuff("a");
  1563. X
  1564. XdoAPPENDcmd:
  1565. X    CLEAROP;
  1566. X    /* Works just like an 'i'nsert on the next character. */
  1567. X    n = RowNumber(Curschar);
  1568. X    AppendPositionToUndoUndobuff(Curschar->index, n);
  1569. X    AppendToUndoUndobuff("a");
  1570. X
  1571. X    if (!lineempty(Curschar))
  1572. X        inc(Curschar);
  1573. X
  1574. X    n = RowNumber(Curschar);
  1575. X    AppendPositionToUndobuff(Curschar->index, n);
  1576. X
  1577. X    startinsert(FALSE);
  1578. X    break;
  1579. X
  1580. X      case 'I':
  1581. X    beginline(TRUE);
  1582. X    ResetBuffers();
  1583. X    AppendToRedobuff("I");
  1584. X    goto doINSERTcmd;
  1585. X    /* FALLTHROUGH */
  1586. X
  1587. X      case 'i':
  1588. X      case K_INSERT:
  1589. X    ResetBuffers();
  1590. X    AppendToRedobuff("i");
  1591. X
  1592. XdoINSERTcmd:
  1593. X    CLEAROP;
  1594. X
  1595. X    n = RowNumber(Curschar);
  1596. X    AppendPositionToUndobuff(Curschar->index, n);
  1597. X    AppendPositionToUndoUndobuff(Curschar->index, n);
  1598. X    AppendToUndoUndobuff("i");
  1599. X
  1600. X    startinsert(FALSE);
  1601. X    break;
  1602. X
  1603. X      case 'o':
  1604. X    CLEAROP;
  1605. X    ResetBuffers();
  1606. X
  1607. X    n = RowNumber(Curschar);
  1608. X    AppendToRedobuff("o");
  1609. X    AppendPositionToUndobuff(Curschar->index, n);
  1610. X    AppendPositionToUndoUndobuff(Curschar->index, n);
  1611. X    AppendToUndoUndobuff("o");
  1612. X
  1613. X    if (OpenForward(!RedrawingDisabled))
  1614. X        startinsert(TRUE);
  1615. X
  1616. X    last_command = 'o';
  1617. X    break;
  1618. X
  1619. X      case 'O':
  1620. X    CLEAROP;
  1621. X    ResetBuffers();
  1622. X
  1623. X    n = RowNumber(Curschar);
  1624. X    AppendToRedobuff("O");
  1625. X    AppendPositionToUndobuff(Curschar->index, n);
  1626. X    AppendPositionToUndoUndobuff(Curschar->index, n);
  1627. X    AppendToUndoUndobuff("O");
  1628. X
  1629. X    if (OpenBackward(!RedrawingDisabled))
  1630. X        startinsert(TRUE);
  1631. X
  1632. X    last_command = 'O';
  1633. X    break;
  1634. X
  1635. X      case 'd':
  1636. X    if (operator == DELETE)    /* handle 'dd' */
  1637. X        goto lineop;
  1638. X    if (Prenum != 0)
  1639. X        opnum = Prenum;
  1640. X    startop = *Curschar;
  1641. X    operator = DELETE;
  1642. X    break;
  1643. X
  1644. X    /*
  1645. X     * Some convenient abbreviations... 
  1646. X     */
  1647. X
  1648. X      case 'x':
  1649. X    if (Prenum)
  1650. X        stuffnumReadbuff(Prenum);
  1651. X    stuffReadbuff("dl");
  1652. X    break;
  1653. X
  1654. X      case 'X':
  1655. X    if (Prenum)
  1656. X        stuffnumReadbuff(Prenum);
  1657. X    stuffReadbuff("dh");
  1658. X    break;
  1659. X
  1660. X      case 'D':
  1661. X    stuffReadbuff("d$");
  1662. X    break;
  1663. X
  1664. X      case 'Y':
  1665. X    if (Prenum)
  1666. X        stuffnumReadbuff(Prenum);
  1667. X    stuffReadbuff("yy");
  1668. X    break;
  1669. X
  1670. X      case 'C':
  1671. X    stuffReadbuff("c$");
  1672. X    break;
  1673. X
  1674. X      case 'c':
  1675. X    if (operator == CHANGE) {    /* handle 'cc' */
  1676. X        CLEAROP;
  1677. X        stuffReadbuff("0c$");
  1678. X        break;
  1679. X    }
  1680. X    if (Prenum != 0)
  1681. X        opnum = Prenum;
  1682. X    startop = *Curschar;
  1683. X    operator = CHANGE;
  1684. X    break;
  1685. X
  1686. X      case 'y':
  1687. X    if (operator == YANK)    /* handle 'yy' */
  1688. X        goto lineop;
  1689. X    if (Prenum != 0)
  1690. X        opnum = Prenum;
  1691. X    startop = *Curschar;
  1692. X    operator = YANK;
  1693. X    break;
  1694. X
  1695. X      case ENABLE_REDRAWING:
  1696. X    RedrawingDisabled = FALSE;
  1697. X    S_NOT_VALID;
  1698. X    break;
  1699. X
  1700. X      case 'p':
  1701. X    if (Yankbuffptr != NULL) {
  1702. X        doput(FORWARD);
  1703. X
  1704. X        stuffReadbuff(ENABLE_REDRAWING_STR);
  1705. X        RedrawingDisabled = TRUE;
  1706. X    } else
  1707. X        beep();
  1708. X    break;
  1709. X
  1710. X      case 'P':
  1711. X    if (Yankbuffptr != NULL) {
  1712. X        doput(BACKWARD);
  1713. X
  1714. X        stuffReadbuff(ENABLE_REDRAWING_STR);
  1715. X        RedrawingDisabled = TRUE;
  1716. X    } else
  1717. X        beep();
  1718. X    break;
  1719. X
  1720. X      case '>':
  1721. X    if (operator == RSHIFT)    /* handle >> */
  1722. X        goto lineop;
  1723. X    if (operator == LSHIFT) {
  1724. X        CLEAROP;
  1725. X        beep();
  1726. X        break;
  1727. X    }
  1728. X    if (Prenum != 0)
  1729. X        opnum = Prenum;
  1730. X    startop = *Curschar;    /* save current position */
  1731. X    operator = RSHIFT;
  1732. X    break;
  1733. X
  1734. X      case '<':
  1735. X    if (operator == LSHIFT)    /* handle << */
  1736. X        goto lineop;
  1737. X    if (operator == RSHIFT) {
  1738. X        CLEAROP;
  1739. X        beep();
  1740. X        break;
  1741. X    }
  1742. X    if (Prenum != 0)
  1743. X        opnum = Prenum;
  1744. X    startop = *Curschar;    /* save current position */
  1745. X    operator = LSHIFT;
  1746. X    break;
  1747. X
  1748. X      case 's':        /* substitute characters */
  1749. X    if (Prenum)
  1750. X        stuffnumReadbuff(Prenum);
  1751. X    stuffReadbuff("cl");
  1752. X    break;
  1753. X
  1754. X      case '?':
  1755. X      case '/':
  1756. X      case ':':
  1757. X    CLEAROP;
  1758. X    readcmdline(c, (char *) NULL);
  1759. X    break;
  1760. X
  1761. X      case 'n':
  1762. X    mtype = MCHAR;
  1763. X    mincl = FALSE;
  1764. X    set_want_col = TRUE;
  1765. X    if (!repsearch(0)) {
  1766. X        CLEAROP;
  1767. X        beep();
  1768. X    }
  1769. X    break;
  1770. X
  1771. X      case 'N':
  1772. X    mtype = MCHAR;
  1773. X    mincl = FALSE;
  1774. X    set_want_col = TRUE;
  1775. X    if (!repsearch(1)) {
  1776. X        CLEAROP;
  1777. X        beep();
  1778. X    }
  1779. X    break;
  1780. X
  1781. X    /*
  1782. X     * Character searches 
  1783. X     */
  1784. X      case 'T':
  1785. X    dir = BACKWARD;
  1786. X    /* FALLTHROUGH */
  1787. X
  1788. X      case 't':
  1789. X    type = 1;
  1790. X    goto docsearch;
  1791. X
  1792. X      case 'F':
  1793. X    dir = BACKWARD;
  1794. X    /* FALLTHROUGH */
  1795. X
  1796. X      case 'f':
  1797. Xdocsearch:
  1798. X    mtype = MCHAR;
  1799. X    mincl = TRUE;
  1800. X    set_want_col = TRUE;
  1801. X    if ((nchar = vgetc()) == ESC)    /* search char */
  1802. X        break;
  1803. X    if (!searchc(nchar, dir, type)) {
  1804. X        CLEAROP;
  1805. X        beep();
  1806. X    }
  1807. X    break;
  1808. X
  1809. X      case ',':
  1810. X    flag = 1;
  1811. X    /* FALLTHROUGH */
  1812. X
  1813. X      case ';':
  1814. X    mtype = MCHAR;
  1815. X    mincl = TRUE;
  1816. X    set_want_col = TRUE;
  1817. X    if (!crepsearch(flag)) {
  1818. X        CLEAROP;
  1819. X        beep();
  1820. X    }
  1821. X    break;
  1822. X
  1823. X    /*
  1824. X     * Function searches 
  1825. X     */
  1826. X
  1827. X      case '[':
  1828. X    dir = BACKWARD;
  1829. X    /* FALLTHROUGH */
  1830. X
  1831. X      case ']':
  1832. X    mtype = MLINE;
  1833. X    set_want_col = TRUE;
  1834. X    if (vgetc() != c) {
  1835. X        CLEAROP;
  1836. X        beep();
  1837. X        break;
  1838. X    }
  1839. X    if (!findfunc(dir)) {
  1840. X        CLEAROP;
  1841. X        beep();
  1842. X    }
  1843. X    break;
  1844. X
  1845. X    /*
  1846. X     * Marks 
  1847. X     */
  1848. X
  1849. X      case 'm':
  1850. X    CLEAROP;
  1851. X    if (!setmark(vgetc()))
  1852. X        beep();
  1853. X    break;
  1854. X
  1855. X      case '\'':
  1856. X    flag = TRUE;
  1857. X    /* FALLTHROUGH */
  1858. X
  1859. X      case '`':
  1860. X    S_CHECK_TOPCHAR_AND_BOTCHAR;
  1861. X    {
  1862. X        LPtr            mtmp;
  1863. X        LPtr            *mark = getmark(vgetc());
  1864. X
  1865. X        if (mark == NULL) {
  1866. X        CLEAROP;
  1867. X        beep();
  1868. X        } else {
  1869. X        mtmp = *mark;
  1870. X        setpcmark();
  1871. X        *Curschar = mtmp;
  1872. X        if (flag)
  1873. X            beginline(TRUE);
  1874. X        }
  1875. X        mtype = flag ? MLINE : MCHAR;
  1876. X        mincl = TRUE;    /* ignored if not MCHAR */
  1877. X        set_want_col = TRUE;
  1878. X    }
  1879. X    break;
  1880. X
  1881. X      case 'r':
  1882. X    CLEAROP;
  1883. X    if (lineempty(Curschar)) {    /* Nothing to replace */
  1884. X        beep();
  1885. X        break;
  1886. X    }
  1887. X    if ((nchar = vgetc()) == ESC)
  1888. X        break;
  1889. X
  1890. X    Prenum = DEFAULT1(Prenum);
  1891. X    n = strlen(Curschar->linep->s) - Curschar->index;
  1892. X    if (n < Prenum) {
  1893. X        beep();
  1894. X        break;
  1895. X    }
  1896. X    ResetBuffers();
  1897. X
  1898. X    nn = RowNumber(Curschar);
  1899. X    AppendPositionToUndobuff(Curschar->index, nn);
  1900. X    AppendPositionToUndoUndobuff(Curschar->index, nn);
  1901. X
  1902. X    while (Prenum > 0) {
  1903. X        AppendToRedobuff("r");
  1904. X        AppendToRedobuff(mkstr(nchar));
  1905. X
  1906. X        AppendToUndobuff("r");
  1907. X        AppendToUndobuff(mkstr(gchar(Curschar)));
  1908. X
  1909. X        AppendToUndoUndobuff("r");
  1910. X        AppendToUndoUndobuff(mkstr(nchar));
  1911. X
  1912. X        pchar(Curschar, nchar);    /* Change current character. */
  1913. X
  1914. X        if (Prenum > 1) {
  1915. X        oneright();
  1916. X        AppendToRedobuff("l");
  1917. X        AppendToUndobuff("l");
  1918. X        AppendToUndoUndobuff("l");
  1919. X        }
  1920. X        Prenum--;
  1921. X    }
  1922. X
  1923. X    CHANGED;
  1924. X    S_LINE_NOT_VALID;
  1925. X    break;
  1926. X
  1927. X      case '~':        /* swap case */
  1928. X    CLEAROP;
  1929. X    if (lineempty(Curschar)) {
  1930. X        beep();
  1931. X        break;
  1932. X    }
  1933. X    ResetBuffers();
  1934. X
  1935. X    n = RowNumber(Curschar);
  1936. X    AppendPositionToUndobuff(Curschar->index, n);
  1937. X    AppendPositionToUndoUndobuff(Curschar->index, n);
  1938. X
  1939. X    Prenum = DEFAULT1(Prenum);
  1940. X    if (Prenum > 0) {
  1941. X        AppendNumberToRedobuff(Prenum);
  1942. X        AppendNumberToUndobuff(Prenum);
  1943. X        AppendNumberToUndoUndobuff(Prenum);
  1944. X    }
  1945. X    AppendToRedobuff("~");
  1946. X    AppendToUndobuff("~");
  1947. X    AppendToUndoUndobuff("~");
  1948. X
  1949. X    while (Prenum > 0) {
  1950. X        c = gchar(Curschar);
  1951. X        if (isalpha(c)) {
  1952. X        if (islower(c))
  1953. X            pchar(Curschar, toupper(c));
  1954. X        else
  1955. X            pchar(Curschar, tolower(c));
  1956. X        }
  1957. X        if (!oneright())
  1958. X        break;
  1959. X        Prenum--;
  1960. X    }
  1961. X
  1962. X    CHANGED;
  1963. X    S_LINE_NOT_VALID;
  1964. X    break;
  1965. X
  1966. X      case UNDO_SHIFTJ:
  1967. X    CLEAROP;
  1968. X    if (UndoInProgress) {
  1969. X        (void) dojoin(FALSE, FALSE);
  1970. X        break;
  1971. X    }
  1972. X    goto doSHIFTJcommand;
  1973. X
  1974. X      case 'J':
  1975. X    CLEAROP;
  1976. XdoSHIFTJcommand:
  1977. X    if (nextline(Curschar) == NULL) {    /* on last line */
  1978. X        beep();
  1979. X        break;
  1980. X    }
  1981. X    ResetBuffers();
  1982. X
  1983. X    temp_Curschar = *Curschar;
  1984. X    nn = strlen(Curschar->linep->s);
  1985. X    if (nn < 0)
  1986. X        nn = 0;
  1987. X    n = RowNumber(&temp_Curschar);
  1988. X
  1989. X    AppendToRedobuff("J");
  1990. X
  1991. X    AppendPositionToUndobuff(nn, n);
  1992. X
  1993. X    AppendPositionToUndoUndobuff(0, n);
  1994. X    AppendToUndoUndobuff("J");
  1995. X
  1996. X    if (linewhite(nextline(Curschar))) {
  1997. X        AppendToUndobuff("a\n");
  1998. X        if (!dojoin(FALSE, TRUE)) {
  1999. X        beep();
  2000. X        break;
  2001. X        }
  2002. X    } else if (lineempty(Curschar)) {
  2003. X        AppendToUndobuff("i\n");
  2004. X        if (!dojoin(FALSE, TRUE)) {
  2005. X        beep();
  2006. X        break;
  2007. X        }
  2008. X    } else {
  2009. X        AppendToUndobuff("dli\n");
  2010. X        if (!dojoin(TRUE, TRUE)) {
  2011. X        beep();
  2012. X        break;
  2013. X        }
  2014. X    }
  2015. X
  2016. X    AppendToUndobuff(ESC_STR);
  2017. X    AppendPositionToUndobuff(nn, n);
  2018. X    break;
  2019. X
  2020. X      case K_CGRAVE:        /* shorthand command */
  2021. X    CLEAROP;
  2022. X    stuffReadbuff(":e #\n");
  2023. X    break;
  2024. X
  2025. X      case 'Z':        /* write, if changed, and exit */
  2026. X    if (vgetc() != 'Z') {
  2027. X        beep();
  2028. X        break;
  2029. X    }
  2030. X    if (Changed) {
  2031. X        if (Filename != NULL) {
  2032. X        if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL))
  2033. X            return;
  2034. X        } else {
  2035. X        emsg("No output file");
  2036. X        return;
  2037. X        }
  2038. X    }
  2039. X    getout(0);
  2040. X    break;
  2041. X
  2042. X      case '.':
  2043. X    CLEAROP;
  2044. X    if (Redobuffptr != NULL) {
  2045. X        stuffReadbuff(Redobuff);
  2046. X
  2047. X        stuffReadbuff(ENABLE_REDRAWING_STR);
  2048. X        RedrawingDisabled = TRUE;
  2049. X    } else
  2050. X        beep();
  2051. X    break;
  2052. X
  2053. X      case 'u':
  2054. X      case K_UNDO:
  2055. X    CLEAROP;
  2056. X    if (UndoInProgress) {
  2057. X        p = UndoUndobuff;
  2058. X        UndoUndobuff = Undobuff;
  2059. X        Undobuff = p;
  2060. X        p = UndoUndobuffptr;
  2061. X        UndoUndobuffptr = Undobuffptr;
  2062. X        Undobuffptr = p;
  2063. X
  2064. X        UndoInProgress = FALSE;
  2065. X        RedrawingDisabled = FALSE;
  2066. X        S_NOT_VALID;
  2067. X    } else if (Undobuffptr != NULL) {
  2068. X        stuffReadbuff(Undobuff);
  2069. X        stuffReadbuff("u");
  2070. X        UndoInProgress = TRUE;
  2071. X        RedrawingDisabled = TRUE;
  2072. X    } else {
  2073. X        beep();
  2074. X    }
  2075. X    break;
  2076. X
  2077. X      default:
  2078. X    CLEAROP;
  2079. X    beep();
  2080. X    break;
  2081. X    }
  2082. X
  2083. X    /*
  2084. X     * If an operation is pending, handle it... 
  2085. X     */
  2086. X    if (finish_op) {        /* we just finished an operator */
  2087. X    if (operator == NOP)    /* ... but it was cancelled */
  2088. X        return;
  2089. X
  2090. X    switch (operator) {
  2091. X
  2092. X      case LSHIFT:
  2093. X      case RSHIFT:
  2094. X        ResetBuffers();
  2095. X
  2096. X        n = RowNumber(&startop);
  2097. X        AppendPositionToUndobuff(startop.index, n);
  2098. X        AppendPositionToUndoUndobuff(startop.index, n);
  2099. X        if (Prenum != 0) {
  2100. X        AppendNumberToRedobuff(Prenum);
  2101. X        AppendNumberToUndobuff(Prenum);
  2102. X        AppendNumberToUndoUndobuff(Prenum);
  2103. X        }
  2104. X        AppendToRedobuff((operator == LSHIFT) ? "<" : ">");
  2105. X        AppendToUndobuff((operator == LSHIFT) ? ">" : "<");
  2106. X        AppendToUndoUndobuff((operator == LSHIFT) ? "<" : ">");
  2107. X        AppendToRedobuff(mkstr(c));
  2108. X        if (c == '>')
  2109. X        AppendToUndobuff("<");
  2110. X        else if (c == '<')
  2111. X        AppendToUndobuff(">");
  2112. X        else
  2113. X        AppendToUndobuff(mkstr(c));
  2114. X        AppendToUndoUndobuff(mkstr(c));
  2115. X
  2116. X        doshift(operator);
  2117. X        break;
  2118. X
  2119. X      case DELETE:
  2120. X        ResetBuffers();
  2121. X
  2122. X        n = RowNumber(&startop);
  2123. X        AppendPositionToUndoUndobuff(startop.index, n);
  2124. X
  2125. X        temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  2126. X        n = RowNumber(&temp_Curschar);
  2127. X        if (Prenum != 0) {
  2128. X        AppendNumberToRedobuff(Prenum);
  2129. X        AppendNumberToUndoUndobuff(Prenum);
  2130. X        }
  2131. X        AppendToRedobuff("d");
  2132. X        AppendToUndoUndobuff("d");
  2133. X        AppendToRedobuff(mkstr(c));
  2134. X        AppendToUndoUndobuff(mkstr(c));
  2135. X        if (nchar != NUL) {
  2136. X        AppendToRedobuff(mkstr(nchar));
  2137. X        AppendToUndoUndobuff(mkstr(nchar));
  2138. X        }
  2139. X        AppendPositionToUndobuff(temp_Curschar.index, n);
  2140. X
  2141. X        dodelete(!UndoInProgress, !UndoInProgress, !UndoInProgress);
  2142. X
  2143. X        AppendPositionToUndobuff(temp_Curschar.index, n);
  2144. X        break;
  2145. X
  2146. X      case YANK:
  2147. X        ResetBuffers();    /* no redo/undo/(undo of undo) on yank... */
  2148. X        if (!doyank())
  2149. X        msg("yank buffer exceeded");
  2150. X        if (!ybcrossline)
  2151. X        *Curschar = startop;
  2152. X        else if (lt(&startop, Curschar))
  2153. X        *Curschar = startop;
  2154. X        break;
  2155. X
  2156. X      case CHANGE:
  2157. X        ResetBuffers();
  2158. X
  2159. X        n = RowNumber(&startop);
  2160. X        AppendPositionToUndoUndobuff(startop.index, n);
  2161. X
  2162. X        temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
  2163. X        n = RowNumber(&temp_Curschar);
  2164. X        if (mtype == MLINE)
  2165. X        AppendPositionToUndobuff(0, n);
  2166. X        else
  2167. X        AppendPositionToUndobuff(temp_Curschar.index, n);
  2168. X
  2169. X        if (Prenum != 0) {
  2170. X        AppendNumberToRedobuff(Prenum);
  2171. X        AppendNumberToUndoUndobuff(Prenum);
  2172. X        }
  2173. X        AppendToRedobuff("c");
  2174. X        AppendToUndoUndobuff("c");
  2175. X        AppendToRedobuff(mkstr(c));
  2176. X        AppendToUndoUndobuff(mkstr(c));
  2177. X        if (nchar != NUL) {
  2178. X        AppendToRedobuff(mkstr(nchar));
  2179. X        AppendToUndoUndobuff(mkstr(nchar));
  2180. X        }
  2181. X        dochange();
  2182. X
  2183. X        last_command = 'c';
  2184. X        break;
  2185. X
  2186. X      default:
  2187. X        beep();
  2188. X    }
  2189. X    operator = NOP;
  2190. X    }
  2191. X}
  2192. X
  2193. X/*
  2194. X * tabinout(shift_type, num) 
  2195. X *
  2196. X * If shift_type == RSHIFT, add a tab to the begining of the next num lines;
  2197. X * otherwise delete a tab from the beginning of the next num lines. 
  2198. X */
  2199. Xstatic void
  2200. Xtabinout(shift_type, num)
  2201. X    int             shift_type;
  2202. X    int             num;
  2203. X{
  2204. X    LPtr           *p;
  2205. X
  2206. X    beginline(FALSE);
  2207. X    while (num-- > 0) {
  2208. X    beginline(FALSE);
  2209. X    if (shift_type == RSHIFT)
  2210. X        inschar(TAB);
  2211. X    else {
  2212. X        if (gchar(Curschar) == TAB)
  2213. X        delchar(TRUE, FALSE);
  2214. X    }
  2215. X    if (num > 0) {
  2216. X        if ((p = nextline(Curschar)) != NULL)
  2217. X        *Curschar = *p;
  2218. X        else
  2219. X        break;
  2220. X    }
  2221. X    }
  2222. X}
  2223. X
  2224. X/*
  2225. X * doshift - handle a shift operation 
  2226. X */
  2227. Xstatic void
  2228. Xdoshift(op)
  2229. X    int             op;
  2230. X{
  2231. X    LPtr            top, bot;
  2232. X    int             nlines;
  2233. X
  2234. X    top = startop;
  2235. X    bot = *Curschar;
  2236. X
  2237. X    if (lt(&bot, &top))
  2238. X    pswap(top, bot);
  2239. X
  2240. X    nlines = cntllines(&top, &bot);
  2241. X    *Curschar = top;
  2242. X    tabinout(op, nlines);
  2243. X
  2244. X    /*
  2245. X     * The cursor position afterward is the prior of the two positions. 
  2246. X     */
  2247. X    *Curschar = top;
  2248. X
  2249. X    /*
  2250. X     * If we were on the last char of a line that got shifted left, then move
  2251. X     * left one so we aren't beyond the end of the line 
  2252. X     */
  2253. X    if (gchar(Curschar) == NUL && Curschar->index > 0)
  2254. X    Curschar->index--;
  2255. X
  2256. X    if (op == RSHIFT)
  2257. X    oneright();
  2258. X    else
  2259. X    oneleft();
  2260. X
  2261. X    S_NOT_VALID;
  2262. X
  2263. X    if (nlines > P(P_RP))
  2264. X    smsg("%d lines %ced", nlines, (op == RSHIFT) ? '>' : '<');
  2265. X}
  2266. X
  2267. X/*
  2268. X * dodelete - handle a delete operation 
  2269. X */
  2270. Xstatic void
  2271. Xdodelete(redraw, setup_for_undo, try_to_yank)
  2272. X    bool_t          redraw;
  2273. X    bool_t          setup_for_undo;
  2274. X    bool_t          try_to_yank;
  2275. X{
  2276. X    LPtr            top, bot;
  2277. X    int             nlines;
  2278. X    int             n;
  2279. X
  2280. X    /*
  2281. X     * Do a yank of whatever we're about to delete. If there's too much stuff
  2282. X     * to fit in the yank buffer, then get a confirmation before doing the
  2283. X     * delete. This is crude, but simple. And it avoids doing a delete of
  2284. X     * something we can't put back if we want. 
  2285. X     */
  2286. X    if (try_to_yank) {
  2287. X    if (!doyank()) {
  2288. X        msg("yank buffer exceeded: press <y> to confirm");
  2289. X        if (vgetc() != 'y') {
  2290. X        emsg("delete aborted");
  2291. X        *Curschar = startop;
  2292. X        return;
  2293. X        }
  2294. X    }
  2295. X    }
  2296. X    top = startop;
  2297. X    bot = *Curschar;
  2298. X
  2299. X    if (lt(&bot, &top))
  2300. X    pswap(top, bot);
  2301. X
  2302. X    *Curschar = top;
  2303. X    nlines = cntllines(&top, &bot);
  2304. X
  2305. X    if (mtype == MLINE) {
  2306. X    if (operator == CHANGE) {
  2307. X        last_command_char = 'a';
  2308. X        delline(nlines - 1);
  2309. X        Curschar->index = 0;
  2310. X        while (delchar(TRUE, FALSE));
  2311. X    } else {
  2312. X        if ((Filetop->linep->next == top.linep) &&
  2313. X        (bot.linep->next == Fileend->linep))
  2314. X        last_command_char = 'a';
  2315. X        else if (bot.linep->next == Fileend->linep)
  2316. X        last_command_char = 'o';
  2317. X        else
  2318. X        last_command_char = 'O';
  2319. X        if (setup_for_undo)
  2320. X        AppendToUndobuff(mkstr(last_command_char));
  2321. X        delline(nlines);
  2322. X    }
  2323. X    } else if (top.linep == bot.linep) {    /* del. within line */
  2324. X    if (!mincl)
  2325. X        dec(&bot);
  2326. X
  2327. X    if (endofline(&bot))
  2328. X        last_command_char = 'a';
  2329. X    else
  2330. X        last_command_char = 'i';
  2331. X    if (setup_for_undo)
  2332. X        AppendToUndobuff(mkstr(last_command_char));
  2333. X    n = bot.index - top.index + 1;
  2334. X    while (n--)
  2335. X        if (!delchar(TRUE, FALSE))
  2336. X        break;
  2337. X    } else {            /* del. between lines */
  2338. X    if (endofline(&top)) {
  2339. X        if (nextline(&top)) {
  2340. X        if (lineempty(nextline(&top)))
  2341. X            last_command_char = 'a';
  2342. X        else
  2343. X            last_command_char = 'i';
  2344. X        } else {
  2345. X        last_command_char = 'a';
  2346. X        }
  2347. X    } else {
  2348. X        last_command_char = 'i';
  2349. X    }
  2350. X    if (setup_for_undo)
  2351. X        AppendToUndobuff(mkstr(last_command_char));
  2352. X
  2353. X    n = Curschar->index;
  2354. X    while (Curschar->index >= n)
  2355. X        if (!delchar(TRUE, FALSE))
  2356. X        break;
  2357. X
  2358. X    top = *Curschar;
  2359. X    *Curschar = *nextline(Curschar);
  2360. X    delline(nlines - 2);
  2361. X    Curschar->index = 0;
  2362. X    n = bot.index;
  2363. X    if (!mincl)
  2364. X        n--;
  2365. X
  2366. X    while (n-- >= 0)
  2367. X        if (!delchar(TRUE, FALSE))
  2368. X        break;
  2369. X    *Curschar = top;
  2370. X    dojoin(FALSE, FALSE);
  2371. X    }
  2372. X
  2373. X    if (mtype == MCHAR && nlines == 1 && redraw && P(P_NU) == FALSE) {
  2374. X    S_LINE_NOT_VALID;
  2375. X    } else {
  2376. X    S_NOT_VALID;
  2377. X    }
  2378. X
  2379. X    if (nlines > P(P_RP))
  2380. X    smsg("%d fewer lines", nlines);
  2381. X
  2382. X    if (setup_for_undo) {
  2383. X    AppendToUndobuff(Yankbuff);
  2384. X    AppendToUndobuff(ESC_STR);
  2385. X    }
  2386. X}
  2387. X
  2388. X/*
  2389. X * dochange - handle a change operation 
  2390. X */
  2391. Xstatic void
  2392. Xdochange()
  2393. X{
  2394. X    LPtr            l;
  2395. X
  2396. X    if (lt(Curschar, &startop))
  2397. X    l = *Curschar;
  2398. X    else
  2399. X    l = startop;
  2400. X
  2401. X    dodelete(FALSE, FALSE, !UndoInProgress);
  2402. X
  2403. X    if ((l.index > Curschar->index) && !lineempty(Curschar))
  2404. X    inc(Curschar);
  2405. X
  2406. X    startinsert(FALSE);
  2407. X}
  2408. X
  2409. Xstatic          bool_t
  2410. Xdoyank()
  2411. X{
  2412. X    LPtr            top, bot;
  2413. X    char           *ybend = &Yankbuff[YANKSIZE - 1];
  2414. X    int             nlines;
  2415. X
  2416. X    Yankbuffptr = Yankbuff;
  2417. X
  2418. X    top = startop;
  2419. X    bot = *Curschar;
  2420. X
  2421. X    if (lt(&bot, &top))
  2422. X    pswap(top, bot);
  2423. X
  2424. X    nlines = cntllines(&top, &bot);
  2425. X
  2426. X    ybtype = mtype;        /* set the yank buffer type */
  2427. X    ybcrossline = FALSE;
  2428. X    if (LINEOF(&top) != LINEOF(&bot))
  2429. X    ybcrossline = TRUE;
  2430. X
  2431. X    if (mtype == MLINE) {
  2432. X    ybcrossline = TRUE;
  2433. X    top.index = 0;
  2434. X    bot.index = strlen(bot.linep->s);
  2435. X    /*
  2436. X     * The following statement checks for the special case of yanking a
  2437. X     * blank line at the beginning of the file. If not handled right, we
  2438. X     * yank an extra char (a newline). 
  2439. X     */
  2440. X    if (dec(&bot) == -1) {
  2441. X        *Yankbuff = NUL;
  2442. X        Yankbuffptr = NULL;
  2443. X        return TRUE;
  2444. X    }
  2445. X    } else {
  2446. X    if (!mincl)
  2447. X        if (!equal(&top, &bot))
  2448. X        dec(&bot);
  2449. X    }
  2450. X
  2451. X    for (; ltoreq(&top, &bot); inc(&top)) {
  2452. X    *Yankbuffptr = (gchar(&top) != NUL) ? gchar(&top) : NL;
  2453. X    Yankbuffptr++;
  2454. X    if (Yankbuffptr >= ybend) {
  2455. X        *Yankbuffptr = NUL;
  2456. X        msg("yank too big for buffer");
  2457. X        ybtype = MBAD;
  2458. X        return FALSE;
  2459. X    }
  2460. X    }
  2461. X
  2462. X    *Yankbuffptr = NUL;
  2463. X
  2464. X    if (operator == YANK)
  2465. X    if (nlines > P(P_RP))
  2466. X        smsg("%d lines yanked", nlines);
  2467. X
  2468. X    return TRUE;
  2469. X}
  2470. X
  2471. Xstatic void
  2472. Xdoput(dir)
  2473. X    int             dir;
  2474. X{
  2475. X    bool_t          type;
  2476. X
  2477. X    if (ybtype == MBAD) {
  2478. X    beep();
  2479. X    return;
  2480. X    }
  2481. X    type = (ybtype == MCHAR);
  2482. X    if (dir == FORWARD)
  2483. X    stuffReadbuff(type ? "a" : "o");
  2484. X    else
  2485. X    stuffReadbuff(type ? "i" : "O");
  2486. X
  2487. X    stuffReadbuff(Yankbuff);
  2488. X    stuffReadbuff(ESC_STR);
  2489. X
  2490. X    if (ybtype != MCHAR)
  2491. X    stuffReadbuff("^");
  2492. X}
  2493. X
  2494. Xstatic void
  2495. Xstartinsert(startln)
  2496. X    int             startln;    /* if set, insert at start of line */
  2497. X{
  2498. X    *Insstart = *Curschar;
  2499. X    if (startln) {
  2500. X    Insstart->index = 0;
  2501. X    }
  2502. X    *Insbuff = NUL;
  2503. X    Insbuffptr = NULL;
  2504. X
  2505. X    State = INSERT;
  2506. X    if (P(P_MO))
  2507. X    msg("Insert Mode");
  2508. X}
  2509. X
  2510. Xvoid
  2511. XResetBuffers()
  2512. X{
  2513. X    if (UndoInProgress)
  2514. X    return;
  2515. X
  2516. X    *Redobuff = NUL;
  2517. X    Redobuffptr = NULL;
  2518. X
  2519. X    *Undobuff = NUL;
  2520. X    Undobuffptr = NULL;
  2521. X
  2522. X    *UndoUndobuff = NUL;
  2523. X    UndoUndobuffptr = NULL;
  2524. X}
  2525. X
  2526. Xvoid
  2527. XAppendToInsbuff(s)
  2528. X    char           *s;
  2529. X{
  2530. X    if (UndoInProgress)
  2531. X    return;
  2532. X
  2533. X    if (Insbuffptr == NULL) {
  2534. X    if ((strlen(s) + 1) < INSERT_SIZE) {
  2535. X        strcpy(Insbuff, s);
  2536. X        Insbuffptr = Insbuff;
  2537. X        return;
  2538. X    }
  2539. X    } else if ((strlen(Insbuff) + strlen(s) + 1) < INSERT_SIZE) {
  2540. X    strcat(Insbuff, s);
  2541. X    return;
  2542. X    }
  2543. X    emsg("Couldn't AppendToInsbuff() - clearing Insbuff\n");
  2544. X    *Insbuff = NUL;
  2545. X    Insbuffptr = NULL;
  2546. X}
  2547. X
  2548. Xvoid
  2549. XAppendToRedobuff(s)
  2550. X    char           *s;
  2551. X{
  2552. X    if (UndoInProgress)
  2553. X    return;
  2554. X
  2555. X    if (Redobuffptr == (char *) (-2)) {
  2556. X    return;
  2557. X    }
  2558. X    if (Redobuffptr == (char *) (-1)) {
  2559. X    Redobuffptr = (char *) (-2);
  2560. X    emsg("Couldn't AppendToRedobuff() - Redobuff corrupt");
  2561. X    return;
  2562. X    }
  2563. X    if (Redobuffptr == NULL) {
  2564. X    if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2565. X        strcpy(Redobuff, s);
  2566. X        Redobuffptr = Redobuff;
  2567. X        return;
  2568. X    }
  2569. X    } else if ((strlen(Redobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2570. X    strcat(Redobuff, s);
  2571. X    return;
  2572. X    }
  2573. X    emsg("Couldn't AppendToRedobuff() - clearing Redobuff");
  2574. X    *Redobuff = NUL;
  2575. X    Redobuffptr = (char *) (-1);
  2576. X}
  2577. X
  2578. Xvoid
  2579. XAppendNumberToRedobuff(n)
  2580. X    int             n;
  2581. X{
  2582. X    char            buf[32];
  2583. X
  2584. X    if (UndoInProgress)
  2585. X    return;
  2586. X
  2587. X    sprintf(buf, "%d", n);
  2588. X    AppendToRedobuff(buf);
  2589. X}
  2590. X
  2591. Xvoid
  2592. XAppendToUndobuff(s)
  2593. X    char           *s;
  2594. X{
  2595. X    if (UndoInProgress)
  2596. X    return;
  2597. X
  2598. X    if (Undobuffptr == (char *) (-2)) {
  2599. X    return;
  2600. X    }
  2601. X    if (Undobuffptr == (char *) (-1)) {
  2602. X    Undobuffptr = (char *) (-2);
  2603. X    emsg("Couldn't AppendToUndobuff() - Undobuff corrupt");
  2604. X    return;
  2605. X    }
  2606. X    if (Undobuffptr == NULL) {
  2607. X    if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2608. X        strcpy(Undobuff, s);
  2609. X        Undobuffptr = Undobuff;
  2610. X        return;
  2611. X    }
  2612. X    } else if ((strlen(Undobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2613. X    strcat(Undobuff, s);
  2614. X    return;
  2615. X    }
  2616. X    emsg("Couldn't AppendToUndobuff() - clearing Undobuff");
  2617. X    *Undobuff = NUL;
  2618. X    Undobuffptr = (char *) (-1);
  2619. X}
  2620. X
  2621. Xvoid
  2622. XAppendNumberToUndobuff(n)
  2623. X    int             n;
  2624. X{
  2625. X    char            buf[32];
  2626. X
  2627. X    if (UndoInProgress)
  2628. X    return;
  2629. X
  2630. X    sprintf(buf, "%d", n);
  2631. X    AppendToUndobuff(buf);
  2632. X}
  2633. X
  2634. Xvoid
  2635. XAppendPositionToUndobuff(column, row)
  2636. X    int             column;
  2637. X    int             row;
  2638. X{
  2639. X    if (UndoInProgress)
  2640. X    return;
  2641. X
  2642. X    AppendNumberToUndobuff(row);
  2643. X    AppendToUndobuff("G");
  2644. X    AppendNumberToUndobuff(column);
  2645. X    if (column)
  2646. X    AppendToUndobuff("l");
  2647. X}
  2648. X
  2649. Xvoid
  2650. XAppendToUndoUndobuff(s)
  2651. X    char           *s;
  2652. X{
  2653. X    if (UndoInProgress)
  2654. X    return;
  2655. X
  2656. X    if (UndoUndobuffptr == (char *) (-2)) {
  2657. X    return;
  2658. X    }
  2659. X    if (UndoUndobuffptr == (char *) (-1)) {
  2660. X    UndoUndobuffptr = (char *) (-2);
  2661. X    emsg("Couldn't AppendToUndoUndobuff() - UndoUndobuff corrupt");
  2662. X    return;
  2663. X    }
  2664. X    if (UndoUndobuffptr == NULL) {
  2665. X    if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
  2666. X        strcpy(UndoUndobuff, s);
  2667. X        UndoUndobuffptr = Undobuff;
  2668. X        return;
  2669. X    }
  2670. X    } else if ((strlen(UndoUndobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
  2671. X    strcat(UndoUndobuff, s);
  2672. X    return;
  2673. X    }
  2674. X    emsg("Couldn't AppendToUndoUndobuff() - clearing UndoUndobuff");
  2675. X    *UndoUndobuff = NUL;
  2676. X    UndoUndobuffptr = (char *) (-1);
  2677. X}
  2678. X
  2679. Xvoid
  2680. XAppendNumberToUndoUndobuff(n)
  2681. X    int             n;
  2682. X{
  2683. X    char            buf[32];
  2684. X
  2685. X    if (UndoInProgress)
  2686. X    return;
  2687. X
  2688. X    sprintf(buf, "%d", n);
  2689. X    AppendToUndoUndobuff(buf);
  2690. X}
  2691. X
  2692. Xvoid
  2693. XAppendPositionToUndoUndobuff(column, row)
  2694. X    int             column;
  2695. X    int             row;
  2696. X{
  2697. X    if (UndoInProgress)
  2698. X    return;
  2699. X
  2700. X    AppendNumberToUndoUndobuff(row);
  2701. X    AppendToUndoUndobuff("G");
  2702. X    AppendNumberToUndoUndobuff(column);
  2703. X    if (column)
  2704. X    AppendToUndoUndobuff("l");
  2705. X}
  2706. X
  2707. Xstatic          bool_t
  2708. Xdojoin(leading_space, strip_leading_spaces)
  2709. X    bool_t          leading_space;
  2710. X    bool_t          strip_leading_spaces;
  2711. X{
  2712. X    int             scol;    /* save cursor column */
  2713. X    int             currsize;    /* size of the current line */
  2714. X    int             nextsize;    /* size of the next line */
  2715. X
  2716. X    if (nextline(Curschar) == NULL)    /* on last line */
  2717. X    return FALSE;
  2718. X
  2719. X    nextsize = strlen(Curschar->linep->next->s);
  2720. X    if (!canincrease(nextsize))
  2721. X    return FALSE;
  2722. X
  2723. X    currsize = strlen(Curschar->linep->s);
  2724. X
  2725. X    while (oneright());        /* to end of line */
  2726. X
  2727. X    strcat(Curschar->linep->s, Curschar->linep->next->s);
  2728. X
  2729. X    /*
  2730. X     * Delete the following line. To do this we move the cursor there
  2731. X     * briefly, and then move it back. Don't back up if the delete made us
  2732. X     * the last line. 
  2733. X     */
  2734. X    Curschar->linep = Curschar->linep->next;
  2735. X    scol = Curschar->index;
  2736. X
  2737. X    if (nextline(Curschar) != NULL) {
  2738. X    delline(1);
  2739. X    Curschar->linep = Curschar->linep->prev;
  2740. X    } else
  2741. X    delline(1);
  2742. X
  2743. X    Curschar->index = scol;
  2744. X
  2745. X    if (currsize)
  2746. X    oneright();        /* go to first char. of joined line */
  2747. X
  2748. X    if (nextsize != 0 && strip_leading_spaces) {
  2749. X    /*
  2750. X     * Delete leading white space on the joined line and insert a single
  2751. X     * space. 
  2752. X     */
  2753. X    while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB) {
  2754. X        delchar(TRUE, TRUE);
  2755. X    }
  2756. X    if (leading_space)
  2757. X        inschar(' ');
  2758. X    }
  2759. X    CHANGED;
  2760. X
  2761. X    return TRUE;
  2762. X}
  2763. X
  2764. X/*
  2765. X * linewhite() - returns TRUE if the line consists only of white space
  2766. X */
  2767. X
  2768. Xbool_t
  2769. Xlinewhite(p)
  2770. X    LPtr           *p;
  2771. X{
  2772. X    register int    i;
  2773. X    register char   c;
  2774. X
  2775. X    i = 1;
  2776. X    c = p->linep->s[0];
  2777. X    while (c != NUL) {
  2778. X    if (c != ' ' && c != '\t')
  2779. X        return (FALSE);
  2780. X    c = p->linep->s[i++];
  2781. X    }
  2782. X
  2783. X    return (TRUE);
  2784. X}
  2785. SHAR_EOF
  2786. echo "End of archive 3 (of 6)"
  2787. # if you want to concatenate archives, remove anything after this line
  2788. exit
  2789.